﻿Imports System.Configuration


''' <summary>
''' PreDefined Rules
''' </summary>
Public Class Rules

#Region "Integer Rules"

    ''' <summary>
    ''' Is Positive Integer
    ''' </summary>
    ''' <remarks>
    ''' For Int32
    ''' 
    ''' Matches to "1-Integer.Max"
    ''' Does not match 0
    ''' 
    ''' </remarks>
    Public Class IsPositiveInteger
        Inherits ConfigurationElement
        Implements IRule(Of String)

        ''' <summary>
        ''' Determines whether the specified input is valid.
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <returns>
        ''' <c>true</c> if the specified input is valid; otherwise, <c>false</c>.
        ''' </returns>
        Public Function IsValid(ByVal input As String) As Boolean Implements IRule(Of String).IsValid
            Return IsInNumericRange.Valid(input, 1, Integer.MaxValue)
        End Function

        ''' <summary>
        ''' Validates the specified input.
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <returns></returns>
        Public Shared Function Valid(ByVal input As String) As Boolean
            Dim IsPositiveInteger As New IsPositiveInteger()
            Return IsPositiveInteger.IsValid(input)
        End Function
    End Class

    ''' <summary>
    ''' Is Negative Integer
    ''' </summary>
    ''' <remarks>
    ''' For Int32
    ''' 
    ''' Matches to Integer.Min-0"
    ''' Does not match 0
    ''' 
    ''' </remarks>
    Public Class IsNegativeInteger
        Implements IRule(Of String)

        ''' <summary>
        ''' Determines whether the specified input is valid.
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <returns>
        ''' <c>true</c> if the specified input is valid; otherwise, <c>false</c>.
        ''' </returns>
        Public Function IsValid(ByVal input As String) As Boolean Implements IRule(Of String).IsValid
            Return IsInNumericRange.Valid(input, Integer.MinValue, -1)
        End Function

        ''' <summary>
        ''' Validates the specified input.
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <returns></returns>
        Public Shared Function Valid(ByVal input As String) As Boolean
            Dim IsNegativeInteger As New IsNegativeInteger()
            Return IsNegativeInteger.IsValid(input)
        End Function
    End Class

    ''' <summary>
    ''' Is Integer within a valid range?
    ''' </summary>
    ''' <remarks>
    ''' For Int32
    ''' </remarks>
    Public Class IsInNumericRange
        Inherits ConfigurationElement
        Implements IRule(Of String)

        ''' <summary>
        ''' Gets or sets the minimum value.
        ''' </summary>
        ''' <value>The min.</value>
        <ConfigurationProperty("min", DefaultValue:=0, IsRequired:=True)> _
        Public Property Min() As Integer
            Get
                Return DirectCast(Me.Item("min"), Integer)
            End Get
            Set(ByVal Value As Integer)
                Me.Item("min") = Value
            End Set
        End Property

        ''' <summary>
        ''' Gets or sets the maximum value.
        ''' </summary>
        ''' <value>The max.</value>
        <ConfigurationProperty("max", IsRequired:=True)> _
        Public Property Max() As Integer
            Get
                Return DirectCast(Me.Item("max"), Integer)
            End Get
            Set(ByVal Value As Integer)
                Me.Item("max") = Value
            End Set
        End Property

        ''' <summary>
        ''' Initializes a new instance of the <see cref="IsInRange" /> class.
        ''' </summary>
        ''' <param name="min">The min.</param>
        ''' <param name="max">The max.</param>
        Public Sub New(ByVal min As Integer, ByVal max As Integer)
            Me.Min = min
            Me.Max = max
        End Sub

        ''' <summary>
        ''' Initializes a new instance of the <see cref="IsInRange" /> class.
        ''' </summary>
        Public Sub New()
        End Sub

        ''' <summary>
        ''' Check if input is in supplied range
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <returns>
        ''' <c>true</c> if the specified input is valid; otherwise, <c>false</c>.
        ''' </returns>
        ''' <remarks></remarks>
        Public Function IsValid(ByVal input As String) As Boolean Implements IRule(Of String).IsValid
            Dim InputParam As New BaseParameter(Of String, Integer)(input, RuleSets.IntegerSet)
            If Not InputParam.IsValid() Then Return False

            Return IsInRangeAsInteger.Valid(InputParam.Value, Min, Max)
        End Function


        ''' <summary>
        ''' Validates the specified input.
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <param name="min">The minimum value.</param>
        ''' <param name="max">The maximum value.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Function Valid(ByVal input As String, ByVal min As Integer, ByVal max As Integer) As Boolean
            Dim IsInNumericRange As New IsInNumericRange(min, max)
            Return IsInNumericRange.IsValid(input)
        End Function
    End Class

    ''' <summary>
    ''' Is Integer
    ''' </summary>
    ''' <remarks>
    ''' For Int32
    ''' </remarks>
    Public Class IsInteger
        Implements IRule(Of String)

        ''' <summary>
        ''' Determines whether the specified input is valid.
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <returns>
        ''' <c>true</c> if the specified input is valid; otherwise, <c>false</c>.
        ''' </returns>
        Public Function IsValid(ByVal input As String) As Boolean Implements IRule(Of String).IsValid
            Dim ValidInteger As Integer
            If Integer.TryParse(input, ValidInteger) Then Return True

            Return False
        End Function

        ''' <summary>
        ''' Validates the specified value.
        ''' </summary>
        ''' <param name="value">The value.</param>
        ''' <returns></returns>
        Public Shared Function Valid(ByVal value As String) As Boolean
            Dim IsInteger As New IsInteger()
            Return IsInteger.IsValid(value)
        End Function

    End Class


   
    ''' <summary>
    ''' Special whitelisting solution for integers, All conditions should mathc to return IsValid().
    ''' </summary>
    ''' <remarks>
    ''' </remarks>
    Public Class WhitelistIntegers
        Implements IRule(Of Integer)

        Private _IntegerSets As New List(Of IntegerRuleDefinition)(5)
        ''' <summary>
        ''' Gets the <c>IntegerRuleDefinition</c> List.
        ''' </summary>
        ''' <value>The integer sets.</value>
        Public ReadOnly Property IntegerSets() As List(Of IntegerRuleDefinition)
            Get
                Return _IntegerSets
            End Get
        End Property

        ''' <summary>
        ''' Adds the Range Check.
        ''' </summary>
        ''' <param name="startInt">The start int.</param>
        ''' <param name="endInt">The end int.</param>
        Public Sub AddRange(ByVal startInt As Integer, ByVal endInt As Integer)
            Me.IntegerSets.Add(New IntegerRuleDefinition(startInt, IntegerRuleDefinition.Conditions.Bigger))
            Me.IntegerSets.Add(New IntegerRuleDefinition(endInt, IntegerRuleDefinition.Conditions.Smaller))
        End Sub


        ''' <summary>
        ''' Adds the Range Check.
        ''' </summary>
        ''' <param name="startInt">The start int.</param>
        ''' <param name="endInt">The end int.</param>
        Public Sub AddRangeIncludingBoundaries(ByVal startInt As Integer, ByVal endInt As Integer)
            Me.IntegerSets.Add(New IntegerRuleDefinition(startInt, IntegerRuleDefinition.Conditions.EqualOrBigger))
            Me.IntegerSets.Add(New IntegerRuleDefinition(endInt, IntegerRuleDefinition.Conditions.EqualOrSmaller))
        End Sub

        ''' <summary>
        ''' Adds a new rule.
        ''' </summary>
        ''' <param name="int">The int.</param>
        ''' <param name="condition">The condition.</param>
        Public Sub AddRule(ByVal int As Integer, ByVal condition As IntegerRuleDefinition.Conditions)
            Me.IntegerSets.Add(New IntegerRuleDefinition(int, condition))
        End Sub

        ''' <summary>
        ''' New Smaller Rule.
        ''' </summary>
        ''' <param name="int">The int.</param>
        Public Sub Smaller(ByVal int As Integer)
            AddRule(int, IntegerRuleDefinition.Conditions.Smaller)
        End Sub

        ''' <summary>
        ''' New Bigger Rule.
        ''' </summary>
        ''' <param name="int">The int.</param>
        Public Sub Bigger(ByVal int As Integer)
            AddRule(int, IntegerRuleDefinition.Conditions.Bigger)
        End Sub

        ''' <summary>
        ''' New Equal Rule.
        ''' </summary>
        ''' <param name="int">The int.</param>
        Public Sub Equal(ByVal int As Integer)
            AddRule(int, IntegerRuleDefinition.Conditions.Equal)
        End Sub

        ''' <summary>
        ''' Determines whether the specified input is valid.
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <returns>
        ''' <c>true</c> if the specified input is valid; otherwise, <c>false</c>.
        ''' </returns>
        Public Function IsValid(ByVal input As Integer) As Boolean Implements IRule(Of Integer).IsValid

            Try

                For Each Rule In Me.IntegerSets
                    If Not Rule.IsValid(input) Then Return False
                Next

                Return True

            Catch ex As Exception
                Return False

            End Try

            Return False
        End Function

        ''' <summary>
        ''' Integer Based Condtional Rule
        ''' </summary>
        Public Structure IntegerRuleDefinition

            ''' <summary>
            ''' Conditions
            ''' </summary>
            Public Enum Conditions
                ''' <summary>
                ''' Equal To
                ''' </summary>
                Equal = 0

                ''' <summary>
                ''' Smaller From
                ''' </summary>
                Smaller = 1

                ''' <summary>
                ''' Bigger From
                ''' </summary>
                Bigger = 2

                EqualOrSmaller = 3
                EqualOrBigger = 4


            End Enum

            Public Int As Integer
            Public Condition As Conditions

            ''' <summary>
            ''' Initializes a new instance of the <see cref="IntegerRuleDefinition" /> struct.
            ''' </summary>
            ''' <param name="int">The int.</param>
            ''' <param name="condition">The condition.</param>
            Public Sub New(ByVal int As Integer, ByVal condition As Conditions)
                Me.Int = int
                Me.Condition = condition
            End Sub

            ''' <summary>
            ''' Determines whether the specified input is valid.
            ''' </summary>
            ''' <param name="input">The input.</param>
            ''' <returns>
            ''' <c>true</c> if the specified input is valid; otherwise, <c>false</c>.
            ''' </returns>
            Public Function IsValid(ByVal input As Integer) As Boolean

                Select Case Me.Condition
                    Case Conditions.Bigger
                        Return input > Int

                    Case Conditions.Equal
                        Return input = Int

                    Case Conditions.Smaller
                        Return input < Int

                    Case Conditions.EqualOrSmaller
                        Return input <= Int

                    Case Conditions.EqualOrBigger
                        Return input >= Int

                    Case Else
                        Throw New NotImplementedException("There is no such condition")
                End Select

            End Function

        End Structure

    End Class


#End Region

#Region "Integer From Integer"

    ''' <summary>
    ''' Is Integer within a valid range?
    ''' </summary>
    ''' <remarks>
    ''' For Int32
    ''' </remarks>
    Public Class IsInRangeAsInteger
        Inherits ConfigurationElement
        Implements IRule(Of Integer)


        ''' <summary>
        ''' Gets or sets the minimum value.
        ''' </summary>
        ''' <value>The min.</value>
        <ConfigurationProperty("min", DefaultValue:=0, IsRequired:=True)> _
        Public Property Min() As Integer
            Get
                Return DirectCast(Me.Item("min"), Integer)
            End Get
            Set(ByVal Value As Integer)
                Me.Item("min") = Value
            End Set
        End Property

        ''' <summary>
        ''' Gets or sets the maximum value.
        ''' </summary>
        ''' <value>The max.</value>
        <ConfigurationProperty("max", IsRequired:=True)> _
        Public Property Max() As Integer
            Get
                Return DirectCast(Me.Item("max"), Integer)
            End Get
            Set(ByVal Value As Integer)
                Me.Item("max") = Value
            End Set
        End Property

        ''' <summary>
        ''' Initializes a new instance of the <see cref="IsInRangeAsInteger" /> class.
        ''' </summary>
        ''' <param name="min">The min.</param>
        ''' <param name="max">The max.</param>
        Public Sub New(ByVal min As Integer, ByVal max As Integer)
            Me.Min = min
            Me.Max = max
        End Sub

        ''' <summary>
        ''' Check if input is in supplied range
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <returns>
        ''' <c>true</c> if the specified input is valid; otherwise, <c>false</c>.
        ''' </returns>
        ''' <remarks></remarks>
        Public Function IsValid(ByVal input As Integer) As Boolean Implements IRule(Of Integer).IsValid
            If input >= Min AndAlso input <= Max Then Return True

            Return False
        End Function


        ''' <summary>
        ''' Is Valid?
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <param name="min">The min.</param>
        ''' <param name="max">The max.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Function Valid(ByVal input As Integer, ByVal min As Integer, ByVal max As Integer) As Boolean
            Dim IsInRangeAsInteger As New IsInRangeAsInteger(min, max)
            Return IsInRangeAsInteger.IsValid(input)
        End Function
    End Class


#End Region

#Region "Listing Rules"

    ''' <summary>
    ''' Character Pattern / Format Rule
    ''' </summary>
    ''' <remarks>
    ''' For advanced requirements use your own rule by implementing IRule() interface or use RegEx rules.
    ''' </remarks>
    Public Class WhiteListCharacters
        Inherits ConfigurationElement
        Implements IRule(Of String)

        Private PropertyLoaded As Boolean

        ''' <summary>
        ''' Gets or sets the Whitelist chars pattern.
        ''' </summary>
        ''' <value>The pattern as string. String will be converted to a Char Array and Char Array will be used as accepted whitelist</value>
        <ConfigurationProperty("pattern")> _
        Public ReadOnly Property DefaultPattern() As String
            Get
                Return DirectCast(Me.Item("pattern"), String)
            End Get
        End Property

        Private _WhiteList As IList(Of Char)
        ''' <summary>
        ''' Gets the Whitelist.
        ''' </summary>
        ''' <value>The Whitelist.</value>
        Private ReadOnly Property WhiteList() As IList(Of Char)
            Get
                If _WhiteList Is Nothing Then _WhiteList = New List(Of Char)

                LoadPropertyPattern()

                Return _WhiteList
            End Get
        End Property

        Private LockObj As New Object

        ''' <summary>
        ''' Loads the property pattern.
        ''' </summary>
        Private Sub LoadPropertyPattern()
            If PropertyLoaded Then Exit Sub

            SyncLock LockObj
                If PropertyLoaded Then Exit Sub 'Double Locking

                For Each Item As Char In DefaultPattern.ToCharArray()
                    Me._WhiteList.Add(Item)
                Next

                PropertyLoaded = True
            End SyncLock
        End Sub


        ''' <summary>
        ''' Adds list to the WhiteList.
        ''' </summary>
        ''' <param name="list">The list.</param>
        Public Sub AddList(ByVal list As IList(Of String))
            For Each Item As Char In list
                Me.WhiteList.Add(Item)
            Next
        End Sub

        ''' <summary>
        ''' Adds characters to the Whitelist.
        ''' </summary>
        ''' <param name="list">The list.</param>
        Public Sub AddList(ByVal list As IList(Of Char))
            For Each Item As Char In list
                Me.WhiteList.Add(Item)
            Next
        End Sub


        ''' <summary>
        ''' Add a string chars to the white listed characters.
        ''' </summary>
        ''' <param name="listPattern">The list pattern.</param>
        Public Sub AddListFromString(ByVal listPattern As String)
            If listPattern Is Nothing Then Exit Sub
            AddList(listPattern.ToCharArray())
        End Sub

        ''' <summary>
        ''' Initializes a new instance of the <see cref="WhiteList " /> class.
        ''' </summary>
        ''' <param name="whitelist">The whitelist.</param>
        Public Sub New(ByVal whitelist As IList(Of Char))
            Me._WhiteList = whitelist
        End Sub

        ''' <summary>
        ''' Initializes a new instance of the <see cref="WhiteListCharacters" /> class.
        ''' </summary>
        Public Sub New()
        End Sub

        ''' <summary>
        ''' Determines whether the specified input is valid.
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <returns>
        ''' <c>true</c> if the specified input is valid; otherwise, <c>false</c>.
        ''' </returns>
        Public Function IsValid(ByVal input As String) As Boolean Implements IRule(Of String).IsValid

            If input Is Nothing Then Return False

            Try
                For Each Chr As Char In input
                    If Not Me.WhiteList.Contains(Chr) Then Return False
                Next Chr

            Catch ex As Exception
                Return False
                Throw

            End Try


            Return True
        End Function


        ''' <summary>
        ''' Check if the input is valid.
        ''' </summary>
        ''' <param name="input">The value.</param>
        ''' <param name="whitelist">The whitelist.</param>
        ''' <returns></returns>
        Public Shared Function Valid(ByVal input As String, ByVal whitelist As IList(Of Char)) As Boolean
            Dim WhiteListCharacters As New WhiteListCharacters(whitelist)
            Return WhiteListCharacters.IsValid(input)
        End Function


        ''' <summary>
        ''' Check if the input is valid.
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <param name="whitelist">The whitelist.</param>
        ''' <returns></returns>
        Public Shared Function Valid(ByVal input As String, ByVal whitelist As String) As Boolean
            Dim WhiteListCharacters As New WhiteListCharacters()
            WhiteListCharacters.AddListFromString(whitelist)
            Return WhiteListCharacters.IsValid(input)
        End Function

    End Class


    ''' <summary>
    ''' White Listing
    ''' </summary>
    ''' <remarks>
    ''' Whitelisting strings in a case sensitive way (Object based comparison)
    ''' </remarks>
    Public Class WhiteListItems
        Implements IRule(Of String)

        Private _WhiteList As IList(Of String)
        Private ReadOnly Property WhiteList() As IList(Of String)
            Get
                If _WhiteList Is Nothing Then _WhiteList = New List(Of String)
                Return _WhiteList
            End Get
        End Property


        ''' <summary>
        ''' Combine list to current WhiteList.
        ''' </summary>
        ''' <param name="list">The list.</param>
        Public Sub AddList(ByVal list As IList(Of String))
            For Each Item As String In list
                Me.WhiteList.Add(Item)
            Next
        End Sub

        Public Sub New(ByVal whitelist As IList(Of String))
            Me._WhiteList = whitelist
        End Sub

        Public Sub New()
        End Sub

        ''' <summary>
        ''' Determines whether the specified input is valid.
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <returns>
        ''' <c>true</c> if the specified input is valid; otherwise, <c>false</c>.
        ''' </returns>
        Public Function IsValid(ByVal input As String) As Boolean Implements IRule(Of String).IsValid
            Return WhiteList.Contains(input)
        End Function


        ''' <summary>
        ''' Validates the specified input.
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <param name="whitelist">The whitelist.</param>
        ''' <returns></returns>
        Public Shared Function Valid(ByVal input As String, ByVal whitelist As IList(Of String)) As Boolean
            Dim WhiteListing As New WhiteListItems(whitelist)
            Return WhiteListing.IsValid(input)
        End Function
    End Class

#End Region


#Region "Data Rules"


    ''' <summary>
    ''' Check string Length (Accepts Null Values as 0 Length)
    ''' </summary>
    ''' <remarks></remarks>
    Public Class IsDataInRange
        Inherits ConfigurationElement
        Implements IRule(Of String)

        ''' <summary>
        ''' Gets or sets the minimum value.
        ''' </summary>
        ''' <value>The min.</value>
        <ConfigurationProperty("min", DefaultValue:=0, IsRequired:=True)> _
        Public Property Min() As Integer
            Get
                Return DirectCast(Me.Item("min"), Integer)
            End Get
            Set(ByVal Value As Integer)
                Me.Item("min") = Value
            End Set
        End Property

        ''' <summary>
        ''' Gets or sets the maximum value.
        ''' </summary>
        ''' <value>The max.</value>
        <ConfigurationProperty("max", IsRequired:=True)> _
        Public Property Max() As Integer
            Get
                Return DirectCast(Me.Item("max"), Integer)
            End Get
            Set(ByVal Value As Integer)
                Me.Item("max") = Value
            End Set
        End Property

        ''' <summary>
        ''' Initializes a new instance of the <see cref="IsDataInRange" /> class.
        ''' </summary>
        ''' <param name="min">The min.</param>
        ''' <param name="max">The max.</param>
        Public Sub New(ByVal min As Integer, ByVal max As Integer)
            Me.Min = min
            Me.Max = max
        End Sub

        ''' <summary>
        ''' Initializes a new instance of the <see cref="IsDataInRange" /> class.
        ''' </summary>
        Public Sub New()
        End Sub

        ''' <summary>
        ''' Initializes a new instance of the <see cref="IsDataInRange" /> class.
        ''' </summary>
        ''' <param name="max">The max.</param>
        Public Sub New(ByVal max As Integer)
            Me.New(0, max)
        End Sub

        ''' <summary>
        ''' Determines whether the specified input is valid.
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <returns>
        ''' <c>true</c> if the specified input is valid; otherwise, <c>false</c>.
        ''' </returns>
        Public Function IsValid(ByVal input As String) As Boolean Implements IRule(Of String).IsValid
            If input Is Nothing Then input = String.Empty
            Return IsInRangeAsInteger.Valid(input.Length, Min, Max)
        End Function

        ''' <summary>
        ''' Validates the specified input.
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <param name="min">The min.</param>
        ''' <param name="max">The max.</param>
        ''' <returns></returns>
        Public Shared Function Valid(ByVal input As String, ByVal min As Integer, ByVal max As Integer) As Boolean
            Dim IsDataRange As New IsDataInRange(min, max)
            Return IsDataRange.IsValid(input)
        End Function

        ''' <summary>
        ''' Valids the specified value.
        ''' </summary>
        ''' <param name="value">The value.</param>
        ''' <param name="max">The max.</param>
        ''' <returns></returns>
        Public Shared Function Valid(ByVal value As String, ByVal max As Integer) As Boolean
            Return Valid(value, 0, max)
        End Function
    End Class



#End Region


#Region "Other Rules"

    ''' <summary>
    ''' Check if object is Null or not?
    ''' </summary>
    ''' <remarks></remarks>
    Public Class IsNotNull
        Inherits ConfigurationElement
        Implements IRule(Of String)

        ''' <summary>
        ''' Determines whether the specified input is valid.
        ''' </summary>
        ''' <param name="input">The input.</param>
        ''' <returns>
        ''' <c>true</c> if the specified input is valid; otherwise, <c>false</c>.
        ''' </returns>
        Public Function IsValid(ByVal input As String) As Boolean Implements IRule(Of String).IsValid
            Return input IsNot Nothing
        End Function

        ''' <summary>
        ''' Determines whether the specified input is valid.
        ''' </summary>
        ''' <param name="value">The value.</param>
        ''' <returns>
        ''' If Object Is Not Nothing retuns True otherwise False
        ''' </returns>
        ''' <remarks></remarks>
        Public Shared Function Valid(ByVal value As String) As Boolean
            Dim IsNotNull As New IsNotNull()
            Return IsNotNull.IsValid(value)
        End Function
    End Class


#End Region

End Class
